--------tested and verified--------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    01:39:57 01/19/2011 
-- Design Name: 
-- Module Name:    ALU - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
USE IEEE.numeric_std.all;
USE work.LCSE.all;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity ALU is

	port(
			Reset : in std_logic;
			Clk : in std_logic;
			u_instruction : in alu_op;-- U-instruction from the cpu
			FlagZ : out std_logic;--Zero flag
			FlagC : out std_logic;--carry flag
			FlagN : out std_logic;--carry bit Nibble flag
			FlagE : out std_logic;--error flag
			Index_Reg: out std_logic_vector(7 downto 0);--index register
			Databus: inout std_logic_vector(7 downto 0)
		);
	end ALU;

architecture Behav of ALU is

---registers of ALU---------------------------------------

signal A_reg:std_logic_vector(7 downto 0);
signal B_reg:std_logic_vector(7 downto 0);
signal ACC_reg:std_logic_vector(7 downto 0);

-------signals for temporary value storage---------------
signal A_s:std_logic_vector(7 downto 0);
signal B_s:std_logic_vector(7 downto 0);
signal ACC_s:std_logic_vector(7 downto 0);
signal Index_s:std_logic_vector(7 downto 0);
--------------Flags------------------------------------------
--0 Flag Z----1 Flag C----2 Flag N----3 Flag E--------------- 
signal Flag_s: std_logic_vector(3 downto 0);--all the flags 

-------signals to enable specific registers-----------------------
signal A_reg_en:std_logic;
signal B_reg_en:std_logic;
signal ACC_reg_en:std_logic;

signal Flag_reg_en:std_logic;
signal Index_reg_en:std_logic;

signal shft_rght_en:std_logic;
signal shft_lft_en:std_logic;
---------------------------------------------------------

begin
	
operation:process(A_reg, B_reg,ACC_reg, u_instruction, Databus)
	begin
	
	case u_instruction is
	
	when  nop =>     -- no operation
	
      ----all registers are disabled----------
		A_reg_en <= '0';
		B_reg_en <= '0';
		ACC_reg_en <= '0';
		Index_reg_en <= '0';
		Flag_reg_en <= '0';
		shft_lft_en <= '0';
		shft_rght_en <= '0';
		
		A_s <= (Others => 'X');
		B_s <= (Others => 'X');
		ACC_s <= (Others => 'X');
		Index_s <= (Others => 'X');
		Flag_s <= (Others => 'X');
		-- external value load
	
	when  op_lda =>--load A register
	----register A is enabled and loaded from the databus----------
	  
		A_reg_en <= '1';
		B_reg_en <= '0';
		ACC_reg_en <= '0';
		Index_reg_en <= '0';
		Flag_reg_en <= '0';
		shft_lft_en <= '0';
		shft_rght_en <= '0';
		
		A_s <= Databus;
		B_s <= (Others => 'X');
		ACC_s <= (Others => 'X');
		Index_s <= (Others => 'X');
		Flag_s <= (Others => 'X');
	
	when	op_ldb=>-- load B register
	 ----register A is enabled and loaded from the databus----------
	  
		A_reg_en <= '0';
		B_reg_en <= '1';
		ACC_reg_en <= '0';
		Index_reg_en <= '0';
		Flag_reg_en <= '0';
		shft_lft_en <= '0';
		shft_rght_en <= '0';
		
		A_s <= (Others => 'X');
		B_s <= Databus;
		ACC_s <= (Others => 'X');
		Index_s <= (Others => 'X');
		Flag_s <= (Others => 'X');
	
	when	op_ldacc =>--load ACC register
	
	  ----register ACC is enabled and loaded from the databus----------
	  
		A_reg_en <= '0';
		B_reg_en <= '0';
		ACC_reg_en <= '1';
		Index_reg_en <= '0';
		Flag_reg_en <= '0';
		shft_lft_en <= '0';
		shft_rght_en <= '0';
		
		A_s <= (Others => 'X');
		B_s <= (Others => 'X');
		ACC_s <= Databus;
		Index_s <= (Others => 'X');
		Flag_s <= (Others => 'X');
	
	when	op_ldid =>--load index register
	
		----register Index  is enabled and loaded from the databus----------
	  
		A_reg_en <= '0';
		B_reg_en <= '0';
		ACC_reg_en <= '0';
		Index_reg_en <= '1';
		Flag_reg_en <= '0';
		shft_lft_en <= '0';
		shft_rght_en <= '0';
		
		A_s <= (Others => 'X');
		B_s <= (Others => 'X');
		ACC_s <= (Others => 'X');
		Index_s <= Databus ;
		Flag_s <= (Others => 'X');
		
		-- internal load
		
	when  op_mvacc2id=> --move from ACC to Index register
	
		A_reg_en <= '0';
		B_reg_en <= '0';
		ACC_reg_en <= '0';
		Index_reg_en <= '1';
		Flag_reg_en <= '0';
		shft_lft_en <= '0';
		shft_rght_en <= '0';
		
		A_s <= (Others => 'X');
		B_s <= (Others => 'X');
		ACC_s <= (Others => 'X');
		Index_s <= ACC_reg ;
		Flag_s <= (Others => 'X');
	
	when	op_mvacc2a=>--move from ACC to A register
	
		A_reg_en <= '1';
		B_reg_en <= '0';
		ACC_reg_en <= '0';
		Index_reg_en <= '0';
		Flag_reg_en <= '0';
		shft_lft_en <= '0';
		shft_rght_en <= '0';
		
		A_s <= ACC_reg ;
		B_s <= (Others => 'X');
		ACC_s <= (Others => 'X');
		Index_s <=(Others => 'X') ;
		Flag_s <= (Others => 'X');
		
	when	op_mvacc2b=>--move from ACC to B register
      
		A_reg_en <= '0';
		B_reg_en <= '1';
		ACC_reg_en <= '0';
		Index_reg_en <= '0';
		Flag_reg_en <= '0';
		shft_lft_en <= '0';
		shft_rght_en <= '0';
		
		A_s <= (Others => 'X')  ;
		B_s <= ACC_reg ;
		ACC_s <= (Others => 'X');
		Index_s <=(Others => 'X') ;
		Flag_s <= (Others => 'X');
		
		-- arithmetic operations
		
	when	op_add=>---add
	
		A_reg_en <= '0';
		B_reg_en <= '0';
		ACC_reg_en <= '1';
		Index_reg_en <= '0';
		Flag_reg_en <= '1';
		shft_lft_en <= '0';
		shft_rght_en <= '0';
		
		A_s<=(others=>'X');
		B_s<=(others=>'X');
		Index_s<=(others=>'X');
		ACC_s<= (A_reg+B_reg);
		
----------Flag C---------------------------------		
		if(((conv_integer (A_reg)))+((conv_integer(B_reg)))> 255) then 
			Flag_s(1) <= '1';
		else 
			Flag_s(1) <= '0';
		end if;
		
--------Flag N-----------------------------------------------
		if((conv_integer(A_reg(3 downto 0)))+(conv_integer(B_reg(3 downto 0)))>15) then   
			Flag_s(2) <= '1';
		else 
			Flag_s(2) <= '0';
		end if;
		
-------------Flag Z-------------------------------------------	
		if ((A_reg + B_reg) = "00000000") then --result =0
			Flag_s(0) <= '1';
		else 
			Flag_s(0) <= '0';
		end if;
		
------------Flag E-----------------------------------------------	
		Flag_s(3) <= '0';
--------------------------------------------------------------------	
	
	when	op_sub=>--subtract
	
		A_reg_en <= '0';
		B_reg_en <= '0';
		ACC_reg_en <= '1';
		Index_reg_en <= '0';
		Flag_reg_en <= '1';
		shft_lft_en <= '0';
		shft_rght_en <= '0';
	
		A_s<=(others=>'X');
		B_s<=(others=>'X');
		Index_s<=(others=>'X');
		ACC_s<= (A_reg - B_reg);
		
----------Flag C--------------------------------		
		if(((conv_integer(A_reg)))-((conv_integer(B_reg)))< 0) then 
			Flag_s(1) <= '1';
		else 
			Flag_s(1) <= '0';
		end if;
		
--------Flag N-----------------------------------------------
		if(((conv_integer(A_reg(3 downto 0)))-(conv_integer(B_reg(3 downto 0))))>15) then   
			Flag_s(2) <= '1';
		else 
			Flag_s(2) <= '0';
		end if;
		
-------------Flag Z-------------------------------------------	
		if ((A_reg - B_reg) = "00000000") then --result =0
			Flag_s(0) <= '1';
		else 
			Flag_s(0) <= '0';
		end if;
		
------------Flag E-----------------------------------------------	
		Flag_s(3) <= '0';
--------------------------------------------------------------------
	
	when	op_shiftl=>--shift left operation
	
		A_reg_en <= '0';
		B_reg_en <= '0';
		ACC_reg_en <= '1';
		Index_reg_en <= '0';
		Flag_reg_en <= '1';
		shft_lft_en <= '1';
		shft_rght_en <= '0';
	
		A_s<=(others=>'X');
		B_s<=(others=>'X');
		Index_s<=(others=>'X');
		ACC_s	 <=(others=>'X');
		
		Flag_s <= "0000";
	
	
	when	op_shiftr=>--shift right operation
		
		A_reg_en <= '0';
		B_reg_en <= '0';
		ACC_reg_en <= '1';
		Index_reg_en <= '0';
		Flag_reg_en <= '1';
		shft_lft_en <= '0';
		shft_rght_en <= '1';
	
		A_s<=(others=>'X');
		B_s<=(others=>'X');
		Index_s<=(others=>'X');
		ACC_s	 <=(others=>'X');
		
		Flag_s <= "0000";
		
		-- logic operations
		
   when  op_and =>--anding operation
	
		A_reg_en <= '0';
		B_reg_en <= '0';
		ACC_reg_en <= '1';
		Index_reg_en <= '0';
		Flag_reg_en <= '1';
		shft_lft_en <= '0';
		shft_rght_en <= '0';
	
		A_s<=(others=>'X');
		B_s<=(others=>'X');
		Index_s<=(others=>'X');
		
		ACC_s<= (A_reg and B_reg);
	
		if (ACC_s = "00000000") then
			Flag_s(0) <= '1';
		else 
			Flag_s(0) <= '0';
		end if;
		
		Flag_s(3 downto 1) <= "000";
	
	
	when	op_or =>--oring operation
		
		A_reg_en <= '0';
		B_reg_en <= '0';
		ACC_reg_en <= '1';
		Index_reg_en <= '0';
		Flag_reg_en <= '1';
		shft_lft_en <= '0';
		shft_rght_en <= '0';
	
		A_s<=(others=>'X');
		B_s<=(others=>'X');
		Index_s<=(others=>'X');
		
		ACC_s<= (A_reg or B_reg);
	
		if (ACC_s = "00000000") then
			Flag_s(0) <= '1';
		else 
			Flag_s(0) <= '0';
		end if;
		
		Flag_s(3 downto 1) <= "000";
		
	
	when	op_xor =>--xoring operation 
		
		A_reg_en <= '0';
		B_reg_en <= '0';
		ACC_reg_en <= '1';
		Index_reg_en <= '0';
		Flag_reg_en <= '1';
		shft_lft_en <= '0';
		shft_rght_en <= '0';
	
		A_s<=(others=>'X');
		B_s<=(others=>'X');
		Index_s<=(others=>'X');
		
		ACC_s<= (A_reg xor B_reg);
	
		if (ACC_s = "00000000") then
			Flag_s(0) <= '1';
		else
			Flag_s(0) <= '0';
		end if;
		
		Flag_s(3 downto 1) <= "000";
		
		-- compare operations
	
	when  op_cmpe=> --compare equal
--after comparison the data is stored in the ACC so ACC is write enabled
		
		A_reg_en <= '0';
		B_reg_en <= '0';
		ACC_reg_en <= '1';
		Index_reg_en <= '0';
		Flag_reg_en <= '1';
		shft_lft_en <= '0';
		shft_rght_en <= '0';
	
		A_s<=(others=>'X');
		B_s<=(others=>'X');
		Index_s<=(others=>'X');
		ACC_s	 <=(others=>'X');	
			
		Flag_s(3 downto 1) <= "000";
	
		if (A_reg = B_reg) then
			Flag_s(0) <= '1';
		else 
			Flag_s(0) <= '0';
		end if;
	
	when	op_cmpl=>--compare less
	
		A_reg_en <= '0';
		B_reg_en <= '0';
		ACC_reg_en <= '1';
		Index_reg_en <= '0';
		Flag_reg_en <= '1';
		shft_lft_en <= '0';
		shft_rght_en <= '0';
	
		A_s<=(others=>'X');
		B_s<=(others=>'X');
		Index_s<=(others=>'X');
		ACC_s	 <=(others=>'X');	
			
		Flag_s(3 downto 1) <= "000";
	
		if (A_reg < B_reg) then
			Flag_s(1) <= '1';
		else
			Flag_s(1) <= '0';
		end if;
	
		A_s<=(others=>'X');
		B_s<=(others=>'X');
		Index_s<=(others=>'X');
		ACC_s	 <=(others=>'X');
	
	when	op_cmpg=>--compare greater
		
		A_reg_en <= '0';
		B_reg_en <= '0';
		ACC_reg_en <= '1';
		Index_reg_en <= '0';
		Flag_reg_en <= '1';
		shft_lft_en <= '0';
		shft_rght_en <= '0';
	
		A_s<=(others=>'X');
		B_s<=(others=>'X');
		Index_s<=(others=>'X');
		ACC_s	 <=(others=>'X');	
			
		Flag_s(3 downto 1) <= "000";
	
		if (A_reg > B_reg) then
			Flag_s(2) <= '1';--nibble flag
		else 
			Flag_s(2) <= '0';
		end if;
		
		-- conversion operations
	when  op_ascii2bin=> --convert ASCII to binary
		
		A_reg_en <= '0';
		B_reg_en <= '0';
		ACC_reg_en <= '0';
		Index_reg_en <= '0';
		Flag_reg_en <= '1';
		shft_lft_en <= '0';
		shft_rght_en <= '0';
	
		A_s<=(others=>'X');
		B_s<=(others=>'X');
		Index_s<=(others=>'X');
		ACC_s	 <=(others=>'X');
	
		Flag_s(2 downto 0) <= "000";
		
		if (A_reg > X"39" or A_reg < X"30") then
			Flag_s(3) <= '1';
			 ACC_s <= X"FF";
		else  
			Flag_s(3) <= '0';
			ACC_s <= (A_reg - X"30"); 
		end if;
	
--		if (A_reg < X"65" or A_reg > X"90") then
--			Flag_s(3) <= '1';
--			ACC_s <= X"FF";
--		else  
--			Flag_s(3) <= '0';
--			ACC_s <= (A_reg - X"30"); 
--		end if;
	
	
	when	op_bin2ascii=> --convert binary to ASCII  
	--characters in hex 41 to 5A-------------
	
		A_reg_en <= '0';
		B_reg_en <= '0';
		ACC_reg_en <= '1';
		Index_reg_en <= '0';
		Flag_reg_en <= '1';
		shft_lft_en <= '0';
		shft_rght_en <= '0';
	
		A_s<=(others=>'X');
		B_s<=(others=>'X');
		Index_s<=(others=>'X');
		ACC_s	 <=(others=>'X');
		
		Flag_s(2 downto 0) <= "000";
	
		if (A_reg > X"09") then
			Flag_s(3) <= '1';
			ACC_s <= X"FF";
		else  
			Flag_s(3) <= '0';
			ACC_s <= (A_reg + X"30"); 
		end if;
	
	--oputput enable	ACC
   when  op_oeacc=>
	
		A_reg_en <= '0';
		B_reg_en <= '0';
		ACC_reg_en <= '0';
		Index_reg_en <= '0';
		Flag_reg_en <= '0';
		shft_lft_en <= '0';
		shft_rght_en <= '0';
	
		A_s<=(others=>'X');
		B_s<=(others=>'X');
		Index_s<=(others=>'X');
		ACC_s	<=(others=>'X');
		Flag_s<=(others=>'X');
		
--------------------------------------------------------------------------------	
	
	end case;
end process operation;


clocking: process (Reset,Clk)
	
	begin

	  if(Reset = '0') then

		A_reg <= (others => '0');
		B_reg <= (others => '0');
		ACC_reg <= (others => '0');
		Index_reg <= (others => '0');
		
		FlagZ <= '0';
		FlagC <= '0';
		FlagN <= '0';
		FlagE <= '0';
  
	  elsif (Clk' event and Clk ='1') then
			
			if (A_reg_en = '1') then
				A_reg <= A_s;
			end if;

			if (B_reg_en = '1') then
				B_reg <= B_s;
			end if;
		
			if (Flag_reg_en = '1') then
			
				FlagZ <= Flag_s(0);
				FlagC <= Flag_s(1);
				FlagN <= Flag_s(2);
				FlagE <= Flag_s(3);
		
			end if;
		
			if (ACC_reg_en = '1') then
				ACC_reg <= ACC_s;
			end if;

			if (Index_reg_en = '1') then
				Index_reg <= Index_s;
			end if;
		
			if (shft_lft_en = '1') then
				ACC_reg(7 downto 1) <= ACC_reg(6 downto 0);
				ACC_reg(0) <= '0';
			 
			elsif (shft_Rght_en = '1') then
				ACC_reg (6 downto 0) <= ACC_reg (7 downto 1);
				ACC_reg (7) <= '0';
			end if;
	end if;
end process clocking;

Databus <= ACC_reg when u_instruction = op_oeacc else "ZZZZZZZZ";

end Behav;

